//import be.kuleuven.cs.som.*;
//LET OP DEFENSIEVE UITWERKING VERVOLLEDIGEN
/**
 * Class that helps changing between scales of temperatures (possibly necessary in the future)
 * @author Florian & Maaike
 * @version 1.0
 */
public enum Temperature {
	
	CELSIUS{
		
		/**
		 * Return the symbol representing Celsius
		 * @return 	The symbol C
		 * 			| result == 'C' 
		 */
		public char getSymbol(){
			return 'C';
		}
		
		/**
		 * Convert the temperature to Celsius
		 * @return	The temperature in Celsius
		 * @throws	IllegalArgumentException
		 * 			The scale to convert to cannot be anything else but Celsius, Fahrenheit or Kelvin
		 * 			| ! isValidScale(scale)
		 */
		public double convertTemperature( double temperature, Temperature scale) throws IllegalArgumentException {
			if(!isValidScale(scale)) {
				throw new IllegalArgumentException("scale does not exist");
			}
			if(scale==FAHRENHEIT)
			{
					return CelsiusToFahrenheit(temperature);
					}
			if(scale==KELVIN){
					return CelsiusToKelvin(temperature);
			}	
			return temperature;
		}	
	},
	
	KELVIN{
		
		/**
		 * Return the symbol representing Kelvin
		 * @return 	The symbol K
		 * 			| result == 'K' 
		 */
		public char getSymbol(){
			return 'K';
		}
		
		/**
		 * Convert the temperature to Kelvin
		 * @return	The temperature in Kelvin
		 * @throws	IllegalArgumentException
		 * 			The scale to convert to cannot be anything else but Celsius, Fahrenheit or Kelvin
		 * 			| ! isValidScale(scale)
		 */
		public double convertTemperature( double temperature, Temperature scale) throws IllegalArgumentException {
			if(!isValidScale(scale)) {
				throw new IllegalArgumentException("scale does not exist");
			}
			if(scale==FAHRENHEIT)
			{
					return KelvinToFahrenheit(temperature);
					}
			if(scale==CELSIUS){
					return KelvinToCelsius(temperature);
			}	
			return temperature;
		}
	},
	
	FAHRENHEIT{
		
		/**
		 * Return the symbol representing Fahrenheit
		 * @return 	The symbol F
		 * 			| result == 'F' 
		 */
        public char getSymbol(){
            return 'F';
        }
		
		/**
		 * Convert the temperature to Fahrenheit
		 * @return	The temperature in Fahrenheit
		 * @throws	IllegalArgumentException
		 * 			The scale to convert to cannot be anything else but Celsius, Fahrenheit or Kelvin
		 * 			| ! isValidScale(scale)
		 */
        public double convertTemperature(double temperature, Temperature scale) throws IllegalArgumentException {
        	if(!isValidScale(scale)) {
				throw new IllegalArgumentException("scale does not exist");
			}
            if(scale == CELSIUS)
                    return FahrenheitToCelsius(temperature);
            if(scale == KELVIN)
                    return FahrenheitToKelvin(temperature);
            return temperature;
    }
 
};
	/**
	 * abstract method that retrieves the symbol which represents the different scales
	 */
	public abstract char getSymbol();
	
	/**
	 * Abstract method that retrieves the temperature in the scale specified by the user.
	 * 
	 * @param 	temperature
	 * 		  	the temperature that we want to convert
	 * @param	scale
	 * 			the scale the user would like to know the temperature in
	 */
	public abstract double convertTemperature(double temperature, Temperature scale);
	
	/**
	 * This method converts temperature in Celsius to temperature in Fahrenheit.
	 * 
	 * @param	temperature
	 * 			a double representing the temperature in degrees
	 * @return	returns a double with the converted temperature
	 * 			| result == (temperature*9)/5 + 32
	 * @throws	OverflowException
	 * 			the multiplication can cause overflow if temperature is too big.
	 */
	private static double CelsiusToFahrenheit(double temperature) throws IllegalArgumentException {
		if(temperature>((Double.MAX_VALUE/9)*5)-32) {
			throw new IllegalArgumentException ("temperature is too big");
		}
		double newTemperature = temperature*9/5 + 32;
		return newTemperature;		
	}
	
	/**
	 * This method converts temperature in Fahrenheit to temperature in Celsius.
	 * 
	 * @param	temperature
	 * 			a double representing the temperature in Fahrenheit
	 * @return	returns a double with the converted temperature
	 * 			| result == (temperature -32)*(5/9)
	 * @throws	OverflowException
	 * 			the multiplication can cause overflow if temperature is too big.
	 * 
	 */
	private static double FahrenheitToCelsius(double temperature) throws IllegalArgumentException {
		double newTemperature = (temperature - 32)*(5/9);
		if(newTemperature < -273.15) {
			throw new IllegalArgumentException("the temperature is too low to exist");
		}
		return newTemperature;
	}

	/**
	 * This method converts temperature in Celsius to temperature in Kelvin.
	 * 
	 * @param	temperature
	 * 			a double representing the temperature in degrees
	 * @return	returns a double with the converted temperature
	 * 			| result == temperature + 273.15;
	 * @throws 	IllegalArgumentException
	 * 			if the amount is already close to MAX_VALUE there could be overflow, these arguments are illegal
	 * @throws	IllegalArgumentException
	 * 			if the temperature is below 0 in Kelvin, or below -273.15 in Celsius, it cannot exist
	 */
	private static double CelsiusToKelvin(double temperature) throws IllegalArgumentException {
		if(temperature > Double.MAX_VALUE-273.15){
			throw new IllegalArgumentException("temperature is too big");
		}
		if (temperature < -273.15) {
			throw new IllegalArgumentException("temperature cannot be below 0 in Kelvin");
		}
		return temperature + 273.15;
	}
	
	/**
	 * This method converts temperature in Kelvin to temperature in Celsius.
	 * 
	 * @param	temperature
	 * 			a double representing the temperature in degrees
	 * @return	returns a double with the converted temperature
	 * 			| result == temperature - 273.15
	 * @throws	IllegalArgumentException
	 * 			temperatures in Kelvin cannot be negative
	 */	
	private static double KelvinToCelsius(double temperature) throws IllegalArgumentException {
		if(temperature<0){
			throw new IllegalArgumentException("temperature can not be negative in Kelvin");
		}
		return temperature - 273.15;
	}
	
	/**
	 * This method converts temperature in Kelvin to temperature in Fahrenheit.
	 * 
	 * @param	temperature
	 * 			a double representing the temperature in degrees
	 * @return	returns a double with the converted temperature
	 * 			| result == CelsiusToFahrenheit(KelvinToCelsius(temperature))
	 * @throws	IllegalArgumentException
	 * 			caused by the use of previous methods
	 */
	private static double KelvinToFahrenheit(double temperature) throws IllegalArgumentException {
		return CelsiusToFahrenheit(KelvinToCelsius(temperature));
	}
	
	/**
	 * This method converts temperature in Fahrenheit to temperature in Kelvin.
	 * 
	 * @param	temperature
	 * 			a double representing the temperature in Fahrenheit
	 * @return	returns a double with the converted temperature
	 * 			| result == CelsiusToKelvin(FahrenheitToCelsius(temperature))
	 * @throws	IllegalArgumentException
	 * 			caused by the use of previous methods
	 */
	private static double FahrenheitToKelvin(double temperature) throws IllegalArgumentException {
		return CelsiusToKelvin(FahrenheitToCelsius(temperature));
	}
	
	public static boolean isValidScale(Temperature scale) {
		return (scale == Temperature.CELSIUS || scale == Temperature.FAHRENHEIT || scale == Temperature.KELVIN);
	}
	
}
